/* $Id: queue.c 13 2006-12-14 21:07:45Z judas $ */

#include <nih/cdefs.h>

#include <nih/list.h>
#include <nih/queue.h>

#include <errno.h>
#include <stdlib.h>

static int check_arg(struct nih_queue *queue, int dir);

struct nih_queue *nih_qcreate_len(ssize_t maxlen)
{
        struct nih_queue *queue;

        queue = calloc(1, sizeof(struct nih_queue));

        if (queue) {
                /* Empty list. */
                queue->list = NULL;
                queue->len = 0;
                queue->maxlen = maxlen;
        }

        return queue;
}

inline int check_arg(struct nih_queue *queue, int dir)
{
        int res;

        res = -1;

        if (!queue)
                errno = EINVAL;

        else if (dir > 0 && queue->maxlen >= 0
                 && queue->len == queue->maxlen) {
                /* Enqueue to full. */
                errno = ERANGE;

        } else if (dir < 0 && queue->len == 0) {
                /* Dequeue from empty. */
                errno = ERANGE;

        } else
                res = 0;

        return res;
}

int nih_qenq(struct nih_queue *queue, const void *value)
{
        int res;
        struct nih_dlist *node;

        res = -1;

        if (check_arg(queue, 0) == 0) {
                node = nih_dcreate(queue->last, NULL, value);
                if (node) {
                        if (!queue->list)
                                queue->list = node;
                        queue->last = node;
                        queue->len++;
                        res = 0;
                }
        }

        return res;
}

int nih_qdeq(struct nih_queue *queue, void **value)
{
        int res;

        res = -1;

        if (!value)
                errno = EINVAL;
        else if (check_arg(queue, -1) == 0) {
                struct nih_dlist *node;

                *value = queue->last->value;
                node = nih_dremove(queue->last);

                if (node || errno == ESRCH) {
                        if (errno == ESRCH)
                                queue->list = queue->last = NULL;
                        else
                                queue->last = node;
                        queue->len--;
                        res = 0;
                }
        }

        return res;
}

int nih_qdestroy_deep(struct nih_queue *queue, nih_free_fnc *free_fnc)
{
        int res;

        res = -1;

        if (!queue)
                errno = EINVAL;
        else {
                (void) nih_ddestroy_deep(queue->list, free_fnc);
                free(queue);
        }

        return res;
}

